/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package ResultEditor.Annotations;

import ResultEditor.ComplexRelationship.iListable;
import java.util.Vector;

/**Data structure of an annotation with its related attributes, such as
 * normal relationships and complex relationships and verifier suggestions.
 *
 * @author Jianwei Leng, University Of Utah
 * @since  2010-06-23
 */
public class Annotation implements Comparable
{

    /**unique annotatio index used in eHOST result editor to indentify
     * all imported or newly created annotaiton.*/
    public int uniqueIndex;
    public String uniqueIndexPhrase;

    /**Mention ID String, contains a instance name and a ID number.
     * ,such as: "SLC_HS_LENG_88765", here, "SLC_HS_LENG_" is the
     * instance name, and "88765" is the ID number.*/
    public String mentionid;

    /**Text content of this annotation*/
    public String annotationText;

    /**The startpoint of this annotation in its original text source.*/
    public int spanstart;

    /**The endpoint of this annotation in its original text source.*/
    public int spanend;

    /**Annotator who created this annotation*/
    public String annotator;

    /**ID of annotator who created this annotation*/
    public String annotatorid;

    /**Annotated Class which this annotation belongs to. Such as annotation
     * words "X-ray" is an instance of class "Test" */
    public String annotationclass;

    /**The time while this annotation was created. Example: "Thu Jun 24 13:23:18 MDT 2010".*/
    public String creationDate;

    /**Comment string of this annotation.*/
    public String comments;

    /**Imported Verifier Suggestions , one or more Strings.*/
    public Vector<String> verifierSuggestion = new Vector<String>();

    /**normal normalrelationships of this annotation, normal is compare to complex normalrelationships. */
    public Vector<NormalRelationship> normalrelationships = new Vector<NormalRelationship>();

    /**Comple Relationship of thi annotation.*/
    public Vector<ComplexRelationship> ComplexRelationships = new Vector<ComplexRelationship>();

    public Vector<suggestion> verifierFound = new Vector<suggestion>();

    /**mention id will be generated while output annotation to xml*/
    public String outputmentionid;

    /** this annotation is visible or not, default value is true */
    public boolean visible = true;

    /** The attributes and relationships have been verified to be in the schema if this is true*/
    private boolean verified = false;

    /** Default constructor.  */
    public Annotation(){
    }



    /**
     * This Constructor is used to create annotations that do not have relationhships or Verifier information.
     * (i.e.) dictionaries, .annotations files, etc.
     * @param mentionID
     * @param annotationText
     * @param spanstart
     * @param spanend
     * @param annotator
     * @param annotatorID
     * @param annotationClass
     * @param creationDate
     */
    public Annotation(String mentionID, String annotationText, int spanstart,
            int spanend, String annotator, String annotatorID,
            String annotationClass, String creationDate) {
        this.mentionid = mentionID;
        this.annotationText = annotationText;
        this.spanstart = spanstart;
        this.spanend = spanend;
        this.annotator = annotator;
        this.annotatorid = annotatorID;
        this.annotationclass = annotationClass;
        this.creationDate = creationDate;

    }
    public ComplexRelationship addComplex(String name, Annotation annot) {
        ComplexRelationship rel = new ComplexRelationship(name);
        rel.addLinked(new eComplex(annot));
        if(this.ComplexRelationships == null)
            this.ComplexRelationships = new Vector<ComplexRelationship>();
        this.ComplexRelationships.add(rel);
        return rel;
    }
    /**set visible flag to this annotation.*/
    public void setVisible(boolean isVisible){
        this.visible = isVisible;
    }

    @Override
    public String toString() {
        return annotationText.toLowerCase();
    }

    public int compareTo(Object object) {
        return this.annotationText.compareTo(object.toString());
    }


    /**quicly compare two annotations, if their basic attributes are same,
     * then return true, otherwise, return false.
     */
    public boolean quickcompareTo(Annotation ann, String filename){
        boolean flag = false;

        ResultEditor.Annotations.Depot depot = new ResultEditor.Annotations.Depot();
        
        try{


            // if comparative object is null
            if(ann==null){
                if(this==null)
                    return true;
                else return false;
            }

            // comparing annotation text
            if(ann.annotationText==null){
                if( this.annotationText!=null )
                    return false;
            }else{
                if( this.annotationText==null )
                    return false;
                else if (this.annotationText.compareTo(ann.annotationText)!=0)
                    return false;
            }

            // comparing annotation span start
            if(ann.spanstart != this.spanstart)
                return false;

            // comparing annotation span end
            if(ann.spanend != this.spanend)
                return false;

            // comparing annotation class
            if(ann.annotationclass==null){
                if( this.annotationclass!=null )
                    return false;
            }else{
                if( this.annotationclass==null )
                    return false;
                else if (this.annotationclass.compareTo(ann.annotationclass)!=0)
                    return false;
            }

            // comparing comments
            if(ann.comments==null){
                if( this.comments!=null )
                    return false;
            }else{
                if( this.comments==null )
                    return false;
                else if (this.comments.compareTo(ann.comments)!=0)
                    return false;
            }

            // complex relationship
            if(ann.ComplexRelationships==null){
                if( this.ComplexRelationships!=null )
                    return false;
            }else{
                if( this.ComplexRelationships==null )
                    return false;
                else{
                    if(ann.ComplexRelationships.size()!=this.ComplexRelationships.size())
                        return false;
                    // compare each sub item
                    for(int i=0;i<ann.ComplexRelationships.size();i++){
                        if(ann.ComplexRelationships.get(i)==null){
                            if( this.ComplexRelationships.get(i) != null )
                                return false;
                        }else{
                            if( this.ComplexRelationships.get(i) == null )
                                return false;
                            else if (this.ComplexRelationships.get(i).getMentionSlotID().compareTo(
                                    ann.ComplexRelationships.get(i).getMentionSlotID())!=0 )
                                return false;
                            else{
                                int size = this.ComplexRelationships.get(i).linkedAnnotations.size();
                                for(int j=0;j<size;j++){
                                    int uid2= this.ComplexRelationships.get(i).linkedAnnotations.get(j).linkedAnnotationIndex;
                                    int uid1= ann.ComplexRelationships.get(i).linkedAnnotations.get(j).linkedAnnotationIndex;

                                    if( uid2 == uid1 ){
                                        continue;
                                    }

                                    //System.out.println("filename="+filename);
                                    //System.out.println("uid1="+uid1+", uid2="+uid2);
                                    Annotation u1, u2;
                                    u1 = depot.getAnnotationByUnique(filename, uid1);
                                    u2 = depot.getAnnotationByUnique(filename, uid2);
                                    if((u1==null)&&(u2==null)){
                                        System.out.println("error 1101032050::1 could not found annotation by uid and filename");
                                        continue;
                                    }
                                    if((u1==null)||(u2==null)){
                                        System.out.println("error 1101032050::2 could not found annotation by uid and filename");
                                        continue;
                                    }

                                    //System.out.println("by uid u1="+u1.toString() + " / u2 ="+u2.toString());
                                    
                                    
                                    if ((u1.spanstart!=u2.spanstart)||(u1.spanend!=u2.spanend)){
                                        //System.out.println("u1="+u1.annotationText + "  u2="+ u2.annotationText);
                                        return false;
                                    }                                                                                                                                                     
                                }
                            }
                        }
                    }
                }
            }


            // compare normal relationship / attributes
            if(ann.normalrelationships==null){
                if(this.normalrelationships!=null)
                    return false;
            }else{
                if(this.normalrelationships==null)
                    return false;
                else{
                    int size1=ann.normalrelationships.size();
                    int size2=this.normalrelationships.size();
                    if(size1 != size2)
                        return false;
                    else{
                        for(int ir=0;ir<size1;ir++){
                            NormalRelationship nr1 = ann.normalrelationships.get(ir);
                            NormalRelationship nr2 = this.normalrelationships.get(ir);

                            if(nr1==null){
                                if(nr2!=null)
                                    return false;
                            }else {
                                if(nr2==null)
                                    return false;
                                else{
                                    if(nr1.relationshipName==null){
                                        if(nr2.relationshipName!=null) return false;
                                    }else{
                                        if (nr2.relationshipName==null)  return false;
                                        else if(nr1.relationshipName.compareTo(nr2.relationshipName)!=0)
                                        return false;
                                    }

                                    

                                    if(nr1.relationshipValue==null){
                                        if(nr2.relationshipValue!=null) return false;
                                    }else{
                                        if (nr2.relationshipValue==null)  return false;
                                    }

                                    int sizev1=nr1.relationshipValue.size();
                                    int sizev2=nr2.relationshipValue.size();
                                    if(sizev1!=sizev2)
                                        return false;

                                    for(int irr=0;irr<sizev1;irr++){
                                        String str1=nr1.relationshipValue.get(irr);
                                        String str2=nr2.relationshipValue.get(irr);

                                        if(str1==null){
                                            if(str2!=null)
                                                return false;
                                        }else {
                                            if(str2==null)
                                                return false;
                                            else{
                                                if(str1.compareTo(str2)!=0)
                                                    return false;
                                            }
                                        }
                                            
                                    }


                                }
                            }
                        }
                    }
                    
                }
            }
           
        }catch(Exception ex){
            System.out.println("error 1101032010:: fail to compare two annotations:"
                + ex.toString());
            return false;
        }
        
        return true;
    }

    @Override
    public boolean equals(Object object)
    {
        // MUSTMUSTMUST error always came out from following codes
        //try{
            if (!object.getClass().isInstance(this))
            {
                return false;
            }
            Annotation compareAgainst = (Annotation) object;

            if (!this.annotationText.toLowerCase().equals(compareAgainst.annotationText.toLowerCase()))
            {
                return false;
            }
            if (!this.annotationclass.equals(compareAgainst.annotationclass))
            {
                return false;
            }

            // compare "annotator"
            if ( this.annotator == null ){
                if (compareAgainst.annotator != null)
                return false;
            } else if (!this.annotator.equals(compareAgainst.annotator)) {
                return false;
            }

            if (!this.creationDate.equals(compareAgainst.creationDate))
            {
                return false;
            }
            if (!(this.spanend == compareAgainst.spanend))
            {
                return false;
            }
            if (!(this.spanstart == compareAgainst.spanstart))
            {
                return false;
            }
        //}catch(Exception ex){
        //    return false;
        //}
        return true;
    }
    
    public Vector<iListable> getNormalRelationshipsForShow()
    {
        //Get original relationships
        Vector<iListable> list = new Vector<iListable>();
        if (normalrelationships != null)
        {
            for (NormalRelationship rel : normalrelationships)
            {
                list.add(rel);
            }
        }
        //Go through each attribute... if it is in the Annotation then get the current value
        //and set that as the selected value else just add it with no selected value.
        Vector<iListable> finalList = new Vector<iListable>();
        for(Relationship.Simple.DataTypes.Attribute attribute: env.Parameters.SimpleRelationshipNames.getAttributes())
        {
            boolean accountedFor = false;
            for(iListable listEntry: list)
            {
                if(((NormalRelationship)listEntry).relationshipName == null||
                        ((NormalRelationship)listEntry).relationshipValue.size() == 0)
                    continue;
                if(listEntry.getSelectedItem(0).equals(attribute.getName()))
                {
                    accountedFor = true;
                    attribute.setString(1, listEntry.getSelectedItem(1));
                    finalList.add(attribute);
                }
            }
            if(!accountedFor)
                finalList.add(attribute);
        }
        //Get all Normal Relationships that Aren't in the current Schema
        if(normalrelationships != null)
        {
            for(NormalRelationship relationship: normalrelationships)
            {
                if(((NormalRelationship)relationship).relationshipName == null||
                        ((NormalRelationship)relationship).relationshipValue.size() == 0)
                    continue;
                boolean accountedFor = false;
                for(Relationship.Simple.DataTypes.Attribute attribute: env.Parameters.SimpleRelationshipNames.getAttributes())
                {
                    if(attribute.getName().equals(relationship.relationshipName))
                        accountedFor = true;
                }
                if(!accountedFor)
                {
                    finalList.add(new Relationship.Simple.DataTypes.Attribute(relationship.relationshipName,relationship.relationshipValue.get(0)));
                }
            }
        }


        return finalList;
    }
    
    /**
     * @return the verified
     */
    public boolean isVerified()
    {
        return verified;
    }

    /**
     * @param verified the verified to set
     */
    public void setVerified(boolean verified)
    {
        this.verified = verified;
    }
}


